<template>
  <div
    class="object-property"
    :class="{ 'object-property--nested': currentDepth > 1 }"
  >
    <!-- 单行布局：属性名、类型、值、操作按钮 -->
    <div class="object-property__row">
      <!-- 属性名 -->
      <div class="object-property__key">
        <el-input
          v-if="editingKey"
          v-model="tempKey"
          @blur="saveKey"
          @keyup.enter="saveKey"
          @keyup.escape="cancelEditKey"
          ref="keyInput"
        />
        <span v-else @dblclick="startEditKey" class="object-property__key-text">
          {{ propertyKey }}
        </span>
      </div>

      <!-- 类型选择 -->
      <div class="object-property__type">
        <el-select v-model="valueType" @change="changeType">
          <el-option label="字符串" value="string" />
          <el-option label="数字" value="number" />
          <el-option label="布尔值" value="boolean" />
          <el-option label="对象" value="object" />
          <el-option label="数组" value="array" />
        </el-select>
      </div>

      <!-- 值输入 -->
      <div class="object-property__value">
        <!-- 字符串输入 -->
        <el-input
          v-if="valueType === 'string'"
          v-model="localValue"
          @input="updateValue"
          placeholder="请输入字符串值"
          style="width: 100%"
        />

        <!-- 数字输入 -->
        <el-input-number
          v-else-if="valueType === 'number'"
          v-model="localValue"
          @change="updateValue"
          placeholder="请输入数字值"
          style="width: 100%"
        />

        <!-- 布尔值选择 -->
        <el-select
          v-else-if="valueType === 'boolean'"
          v-model="localValue"
          @change="updateValue"
          style="width: 100%"
        >
          <el-option label="true" :value="true" />
          <el-option label="false" :value="false" />
        </el-select>

        <!-- 对象和数组显示为只读 -->
        <el-input
          v-else-if="valueType === 'object'"
          :model-value="`{${Object.keys(localValue || {}).length} 个属性}`"
          readonly
        />

        <el-input
          v-else-if="valueType === 'array'"
          :model-value="`[${(localValue || []).length} 个元素]`"
          readonly
        />
      </div>

      <!-- 操作按钮 -->
      <div class="object-property__actions">
        <el-button
          v-if="
            valueType === 'object' &&
            allowAddProperty &&
            currentDepth < maxDepth
          "
          @click="addNestedProperty"
          type="primary"
          circle
          title="添加子属性"
        >
          <el-icon><Plus /></el-icon>
        </el-button>
        <el-button
          v-if="valueType === 'array'"
          @click="addArrayItem"
          type="primary"
          circle
          title="添加数组项"
        >
          <el-icon><Plus /></el-icon>
        </el-button>
        <el-button
          v-if="allowDelete"
          @click="deleteProperty"
          type="danger"
          circle
          title="删除属性"
        >
          <el-icon><Delete /></el-icon>
        </el-button>
      </div>
    </div>

    <!-- 嵌套内容（对象和数组的子项） -->
    <div
      v-if="valueType === 'object' && Object.keys(localValue || {}).length > 0"
      class="object-property__nested"
    >
      <ObjectProperty
        v-for="(nestedValue, nestedKey) in localValue"
        :key="nestedKey"
        :property-key="nestedKey"
        :value="nestedValue"
        :path="[...path, nestedKey]"
        :allow-delete="allowDelete"
        :allow-add-property="allowAddProperty"
        :max-depth="maxDepth"
        :current-depth="currentDepth + 1"
        @update:value="updateNestedValue"
        @delete="deleteNestedProperty"
        @rename-key="renameNestedProperty"
      />
    </div>

    <div
      v-if="valueType === 'array' && (localValue || []).length > 0"
      class="object-property__nested"
    >
      <ObjectProperty
        v-for="(item, index) in localValue"
        :key="index"
        :property-key="`[${index}]`"
        :value="item"
        :path="[...path, index]"
        :allow-delete="true"
        :allow-add-property="allowAddProperty"
        :max-depth="maxDepth"
        :current-depth="currentDepth + 1"
        @update:value="updateArrayItem"
        @delete="deleteArrayItem"
        @rename-key="renameArrayItemKey"
      />
    </div>
  </div>
</template>

<script>
import { defineComponent, ref, computed, watch, nextTick } from 'vue';
import { ElMessageBox, ElMessage } from 'element-plus';
import { Plus, Delete } from '@element-plus/icons-vue';

export default defineComponent({
  name: 'ObjectProperty',
  components: {
    Plus,
    Delete,
  },
  props: {
    propertyKey: {
      type: [String, Number],
      required: true,
    },
    value: {
      type: [String, Number, Boolean, Object, Array],
      default: '',
    },
    path: {
      type: Array,
      required: true,
    },
    allowDelete: {
      type: Boolean,
      default: true,
    },
    allowAddProperty: {
      type: Boolean,
      default: true,
    },
    maxDepth: {
      type: Number,
      default: 10,
    },
    currentDepth: {
      type: Number,
      default: 1,
    },
  },
  emits: ['update:value', 'delete', 'rename-key'],
  setup(props, { emit }) {
    const localValue = ref(props.value);
    const editingKey = ref(false);
    const tempKey = ref(props.propertyKey);
    const keyInput = ref(null);

    // 计算值类型
    const valueType = computed({
      get() {
        if (Array.isArray(localValue.value)) return 'array';
        if (typeof localValue.value === 'object' && localValue.value !== null)
          return 'object';
        if (typeof localValue.value === 'boolean') return 'boolean';
        if (typeof localValue.value === 'number') return 'number';
        return 'string';
      },
      set(newType) {
        switch (newType) {
          case 'string':
            localValue.value = '';
            break;
          case 'number':
            localValue.value = 0;
            break;
          case 'boolean':
            localValue.value = false;
            break;
          case 'object':
            localValue.value = {};
            break;
          case 'array':
            localValue.value = [];
            break;
        }
        updateValue();
      },
    });

    // 监听外部值变化
    watch(
      () => props.value,
      (newValue) => {
        localValue.value = newValue;
      },
      { deep: true },
    );

    const updateValue = () => {
      emit('update:value', props.path, localValue.value);
    };

    const changeType = () => {
      updateValue();
    };

    const deleteProperty = async () => {
      try {
        await ElMessageBox.confirm('确定要删除这个属性吗？', '删除确认', {
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          type: 'warning',
        });
        emit('delete', props.path);
      } catch {
        // 用户取消操作
      }
    };

    // 键名编辑
    const startEditKey = () => {
      editingKey.value = true;
      tempKey.value = props.propertyKey;
      nextTick(() => {
        keyInput.value?.focus();
      });
    };

    const saveKey = () => {
      const trimmedNewKey = tempKey.value.trim();
      if (trimmedNewKey && trimmedNewKey !== props.propertyKey) {
        emit('rename-key', props.path, props.propertyKey, trimmedNewKey);
      } else if (!trimmedNewKey) {
        ElMessage.warning('属性名不能为空');
        tempKey.value = props.propertyKey; // 恢复旧键名
      }
      editingKey.value = false;
    };

    const cancelEditKey = () => {
      tempKey.value = props.propertyKey;
      editingKey.value = false;
    };

    // 嵌套对象操作
    const addNestedProperty = async () => {
      try {
        const { value: newKey } = await ElMessageBox.prompt(
          '请输入属性名',
          '添加属性',
          {
            confirmButtonText: '确定',
            cancelButtonText: '取消',
            inputPattern: /\S+/,
            inputErrorMessage: '属性名不能为空',
          },
        );

        const key = newKey.trim();
        if (localValue.value.hasOwnProperty(key)) {
          ElMessage.warning('属性名已存在');
          return;
        }

        localValue.value = { ...localValue.value, [key]: '' };
        updateValue();
      } catch {
        // 用户取消操作
      }
    };

    const updateNestedValue = (path, value) => {
      emit('update:value', path, value);
    };

    const deleteNestedProperty = (path) => {
      emit('delete', path);
    };

    const renameNestedProperty = (path, oldKey, newKey) => {
      emit('rename-key', path, oldKey, newKey);
    };

    // 数组操作
    const addArrayItem = () => {
      localValue.value = [...(localValue.value || []), ''];
      updateValue();
    };

    const updateArrayItem = (path, value) => {
      emit('update:value', path, value);
    };

    const deleteArrayItem = (path) => {
      emit('delete', path);
    };

    const renameArrayItemKey = (path, oldKey, newKey) => {
      // 数组项的键名通常是索引，不应该被修改。如果需要修改数组项的属性，那应该是嵌套对象内部的属性。
      // 这里可以根据实际需求决定是否允许修改数组项的“键名”（即索引）。
      // 如果不允许，可以不触发事件或给出警告。
      // 如果允许，则需要特殊处理，因为数组的“键名”是其索引，修改索引会改变数组结构。
      // 考虑到当前组件设计，数组项的 propertyKey 是 `[index]` 形式，通常不直接修改。
      // 如果用户双击 `[index]` 尝试修改，可以给出提示或忽略。
      // 为了保持一致性，我们仍然向上冒泡事件，由父组件决定如何处理。
      emit('rename-key', path, oldKey, newKey);
    };

    return {
      localValue,
      valueType,
      editingKey,
      tempKey,
      keyInput,
      updateValue,
      changeType,
      deleteProperty,
      startEditKey,
      saveKey,
      cancelEditKey,
      addNestedProperty,
      updateNestedValue,
      deleteNestedProperty,
      renameNestedProperty,
      addArrayItem,
      updateArrayItem,
      deleteArrayItem,
      renameArrayItemKey,
    };
  },
});
</script>

<style scoped>
.object-property {
  margin-bottom: 8px;
  width: 100%;
  box-sizing: border-box;
}

.object-property--nested {
  border-left: 3px solid var(--el-color-primary);
  padding-left: 16px;
}

.object-property__row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 0px 5px;
  border: 1px solid var(--el-border-color-light);
  border-radius: 4px;
  background: var(--el-fill-color-extra-light);
  box-sizing: border-box;
  width: 100%;
}

.object-property__key {
  flex: 0 0 120px;
  min-width: 180px;
  width: auto;
}

.object-property__key-text {
  font-weight: 600;
  cursor: pointer;
  padding: 0px 8px;
  border-radius: 4px;
  transition: background-color 0.2s;
  display: inline-block;
  width: 100%;
  box-sizing: border-box;
  font-size: 14px;
}

.object-property__key-text:hover {
  background: var(--el-fill-color-light);
}

.object-property__type {
  flex: 0 0 100px;
  min-width: 100px;
}

.object-property__value {
  /* flex: 1; */
  min-width: 150px;
  width: 100%;
}

.object-property__actions {
  flex: 0 0 auto;
  display: flex;
  gap: 6px;
}

.object-property__nested {
  margin-top: 8px;
  width: 100%;
  box-sizing: border-box;
}
</style>
